package org.itboys.pay.alipay;

import com.alibaba.fastjson.JSON;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayTradeAppPayModel;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.*;
import com.alipay.api.response.AlipayTradeAppPayResponse;
import com.alipay.api.response.AlipayTradeCancelResponse;
import com.alipay.api.response.AlipayTradeQueryResponse;
import com.alipay.api.response.AlipayTradeRefundResponse;
import org.itboys.commons.CommonConstants;
import org.itboys.pay.constant.AlipayConfig;
import org.itboys.pay.constant.PayConstants;
import org.itboys.pay.tools.RSA;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

/**
 * 支付宝APP支付
 * @author huml
 *
 */
public class AlipayMobileService {

	protected static Logger logger = LoggerFactory.getLogger(AlipayMobileService.class);

	/**
	 * 支付宝app支付
	 * @param pid
	 * @param notifyUrl
	 * @param outTradeNo
	 * @param subject
	 * @param partner
	 * @param amount
	 * @param body
	 * @param privateKey
	 * @return
	 * @throws Exception
	 */
	public static String appPay(String pid, String notifyUrl, String outTradeNo, String subject,
						 String partner, String amount, String body, String privateKey) throws Exception{
		String[] parameters={
				"service=\"mobile.securitypay.pay\"",//固定值
				"partner=\""+pid+"\"",//商户号
				"_input_charset=\"utf-8\"",
				"notify_url=\""+notifyUrl+"\"",//通知地址
				"out_trade_no=\""+outTradeNo+"\"",//商户内部订单号
				"subject=\"" + subject + "\"",//说明
				"payment_type=\"1\"",//固定值
				"seller_id=\""+partner+"\"",//账户
				"total_fee=\"" + amount + "\"",//支付金额（元）
				"body=\""+body+"\"",//标题
				"it_b_pay=\"30m\""
		};
		return signAllString(parameters, privateKey);
	}

	/**
	 * 新版的app支付参数生成
	 * @param appId  支付宝分配给开发者的应用ID

	 * @param amount  支付金额
	 * @param outTradeNo  订单编号
	 * @param notifyUrl  回调地址
	 * @param privateKey  私钥
	 * @param body  描述
	 * @param subject  标题
	 * @return
	 * @throws Exception
	 */
	public static String newAppPay(String appId, String amount, String outTradeNo,
								   String notifyUrl, String privateKey, String body, String subject, String publicKey) throws Exception{
//		String result = "app_id="+appId+"&biz_content={\"timeout_express\":\"30m\"," +
//                "\"product_code\":\"QUICK_MSECURITY_PAY\",\"total_amount\":\""+amount+"\",\"subject\":\""+subject+"\",\"body\":\""+body+"\"," +
//                "\"out_trade_no\":\""+outTradeNo+"\"}&charset=utf-8&format=json&method=alipay.trade.app.pay&" +
//                "notify_url="+notifyUrl+"&sign_type=RSA&timestamp="+ TimeUtils.format(new Date(), CommonConstants.DATE.FORMAT_DEFAULT)+"&version=1.0";
//        String sign = URLEncoder.encode(RSA.sign(result, privateKey, AlipayConfig.input_charset), AlipayConfig.input_charset);
//		result = "app_id="+URLEncoder.encode(appId, AlipayConfig.input_charset)+"&biz_content="+URLEncoder.encode("{\"timeout_express\":\"30m\",\"product_code\":\"QUICK_MSECURITY_PAY\",\"total_amount\":\""+amount+"\",\"subject\":\""+subject+"\",\"body\":\""+body+
//				"\",\"out_trade_no\":\""+outTradeNo+"\"}", AlipayConfig.input_charset)+"&charset="+URLEncoder.encode(AlipayConfig.input_charset, AlipayConfig.input_charset)+
//				"&format="+URLEncoder.encode(AlipayConfig.format, AlipayConfig.input_charset)+"&method="+URLEncoder.encode("alipay.trade.app.pay", AlipayConfig.input_charset)+"&" +
//				"notify_url="+URLEncoder.encode(notifyUrl, AlipayConfig.input_charset)+"&sign_type="+URLEncoder.encode("RSA2", AlipayConfig.input_charset)+"&timestamp="+
//				URLEncoder.encode(TimeUtils.format(new Date(), CommonConstants.DATE.FORMAT_DEFAULT), AlipayConfig.input_charset)+"&version=" + URLEncoder.encode("1.0", AlipayConfig.input_charset) +
//				"&" + URLEncoder.encode(sign, AlipayConfig.input_charset);

		//实例化客户端
		AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.ALI_OPENAPI_URL, appId,
				privateKey, AlipayConfig.format, CommonConstants.DEFAULT_CHARSET, publicKey, "RSA2"); //获得初始化的AlipayClient
//实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称：alipay.trade.app.pay
		AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
//SDK已经封装掉了公共参数，这里只需要传入业务参数。以下方法为sdk的model入参方式(model和biz_content同时存在的情况下取biz_content)。
		AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
		model.setBody(body);
		model.setSubject(subject);
		model.setOutTradeNo(outTradeNo);
		model.setTimeoutExpress("30m");
		model.setTotalAmount(amount);
		model.setProductCode("QUICK_MSECURITY_PAY");
		request.setBizModel(model);
		request.setNotifyUrl(notifyUrl);
		//这里和普通的接口调用不同，使用的是sdkExecute
		AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);
		logger.info("**********alipay body*************" + response.getBody());
		return response.getBody();

		//return result;
	}
	private static String signAllString(String[] array, String privateKey) throws Exception{
		StringBuffer sb = new StringBuffer("");
		for (int i = 0; i < array.length; i++) {
			if(i==(array.length-1)){
				sb.append(array[i]);
			}else{
				sb.append(array[i]+"&");
			}
		}
		System.out.println(sb.toString());
		String sign = "";
		try {
			sign = URLEncoder.encode(RSA.sign(sb.toString(), privateKey, AlipayConfig.input_charset), AlipayConfig.input_charset);
		} catch (UnsupportedEncodingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		sb.append("&sign=\"" + sign + "\"");
		sb.append("&sign_type=\"RSA\"");
		return sb.toString();
	}

	/**
	 * 支付宝退款
	 * @param refundNo  退款编号(支持一笔订单多次退款)
	 * @param outTradeNo  订单标号
	 * @param totalFee  退款金额
	 * @param appId
	 * @param privateKey
	 * @param publicKey
	 * @return  成功返回该笔订单已退款的总金额   失败返回fail
	 * @throws Exception
	 */
	public static String refund(String refundNo, String outTradeNo, String totalFee,
								String appId, String privateKey, String publicKey) throws Exception{
//		Map<String, String> sParaTemp = Maps.newHashMap();
//		sParaTemp.put("service", "refund_fastpay_by_platform_pwd");
//		sParaTemp.put("partner", PayConfigHolder.getAlipayPartner());
//		sParaTemp.put("_input_charset", AlipayConfig.input_charset);
//		sParaTemp.put("notify_url", refundNotifyUrl);
//		sParaTemp.put("seller_user_id", PayConfigHolder.getAlipayPartner());
//		sParaTemp.put("refund_date", TimeUtils.format(new Date(), CommonConstants.DATE.FORMAT_DEFAULT));
//		sParaTemp.put("batch_no", outTradeNo);
//		sParaTemp.put("batch_num", "1");
//		sParaTemp.put("detail_data", outTradeNo+"^"+totalFee+"^"+"协商退款");
//		String result = AlipaySubmit.buildRequest(sParaTemp, "post", "确认退款");
//		return result;

		AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.ALI_OPENAPI_URL, appId,
				privateKey, AlipayConfig.format, CommonConstants.DEFAULT_CHARSET, publicKey, "RSA2"); //获得初始化的AlipayClient
		AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();//创建API对应的request类
		request.setBizContent("{" +
				"\"out_trade_no\":\""+outTradeNo+"\"," +
				"\"trade_no\":\"\"," +
				"\"out_request_no\":\""+refundNo+"\"," +
				"\"refund_amount\":\""+totalFee+"\"" +
				"}");//设置业务参数
		AlipayTradeRefundResponse response = alipayClient.execute(request);//通过alipayClient调用API，获得对应的response类
		logger.info("***********退款成结果**********" + JSON.toJSONString(response));
		// 根据response中的结果继续业务逻辑处理
		if (response.isSuccess()){
			return CommonConstants.SUCCESS;
		} else {
			return CommonConstants.FAIL;
		}
	}

	/**
	 * 支付宝手机支付 验证异步回调并返回结果
	 * @return AlipayWapResult 
	 */
	@SuppressWarnings("rawtypes")
	public static AlipayWapResult notifyResult(HttpServletRequest request, String aliPublicKey) throws Exception{
		AlipayWapResult result = new AlipayWapResult();
		Map<String,String> params = new HashMap<String,String>();
		Map requestParams = request.getParameterMap();
		for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext();) {
			String name = (String) iter.next();
			String[] values = (String[]) requestParams.get(name);
			String valueStr = "";
			for (int i = 0; i < values.length; i++) {
				valueStr = (i == values.length - 1) ? valueStr + values[i]
						: valueStr + values[i] + ",";
			}
			logger.info("***组装支付宝返回参数****"+name+"*******" + valueStr);
			//乱码解决，这段代码在出现乱码时使用。如果mysign和sign不相等也可以使用这段代码转化
			//valueStr = new String(valueStr.getBytes("ISO-8859-1"), "UTF-8");
			params.put(name, valueStr);
		}


		//商户订单号
		String out_trade_no = params.get(PayConstants.OUT_TRADE_NO);
		logger.info("***组装支付宝返回参数结果--------------商户订单号****"+params.get(PayConstants.OUT_TRADE_NO));
		result.setOut_trade_no(out_trade_no);
		//支付宝交易号
		String trade_no = params.get(PayConstants.AliPay.TRADE_NO);
		logger.info("***组装支付宝返回参数结果--------------支付号****"+params.get(PayConstants.AliPay.TRADE_NO));
		result.setTrade_no(trade_no);
		//交易状态
		String trade_status = params.get(PayConstants.AliPay.TRADE_STATUS);
		logger.info("***组装支付宝返回参数结果--------------交易状态****"+ params.get(PayConstants.AliPay.TRADE_STATUS));
		result.setTrade_status(trade_status);
		//交易金额
		//String price = params.get(PayConstants.AliPay.TRADE_PRICE);
		String price = params.get("total_amount");
		logger.info("***组装支付宝返回参数结果--------------交易金额****"+ params.get("total_amount"));


		result.setPrice(new BigDecimal(price));
		logger.info("***组装支付宝返回参数结果--------------交易金额2****"+ result.getPrice());
		logger.info("***公钥--------------****"+ aliPublicKey);
		//调用支付宝工具类完成签名校验
		logger.info("***验证-2****"+  result.getPrice());
		logger.info("***验证-2 ---param****"+  (params==null)+ "----params 大小---"+params.size());

		boolean signVerified = AlipaySignature.rsaCheckV1(params, aliPublicKey, AlipayConfig.input_charset, "RSA2");
		logger.info("***验证-1****"+  result.getPrice());
		logger.info("***验证-1 ---param****"+  (params==null)+ "----params 大小---"+params.size());
		if(signVerified){//验证成功
			logger.info("***验证1****"+  result.getPrice());

			if(trade_status.equals(PayConstants.AliPay.TRADE_FINISHED)){
				result.setVerify_result(true);
				logger.info("***验证2****"+  result.getPrice());
			;
			} else if (trade_status.equals(PayConstants.AliPay.TRADE_SUCCESS)){
				result.setVerify_result(true);
				logger.info("***验证3****"+  result.getPrice());

			}
		}else{//验证失败
			result.setVerify_result(false);
			logger.info("***验证4****"+  result.getPrice());

		}
		logger.info("***组装支付宝返回参数结果--------------交易金额3****"+  result.getPrice());
		return result;
	}
	
	/**
	 * 当面付-扫码付  商户生成支付二维码
	 * @param appId  商户appid
	 * @param privateKey  商户私钥
	 * @param publicKey  商户公钥
	 * @param outTradeNo  商户订单编号
	 * @param totalAmount  支付金额
	 * @param subject  订单标题
	 * @param notifyUrl  异步回调地址(非必传)
	 * @param storeId  商户门店编号
	 * @param timeoutExpress  交易超时时间
	 * @param path  二维码存放地址
	 * @return
	 * @throws Exception
	 */
	/*public static String createShopTwocode(String appId, String privateKey, String publicKey,
								  String outTradeNo, String totalAmount, String subject, String notifyUrl,
									String storeId, String timeoutExpress, String path) throws Exception{
		AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.ALI_OPENAPI_URL,
				appId,privateKey,AlipayConfig.format, CommonConstants.DEFAULT_CHARSET,publicKey, "RSA2");//获得初始化的AlipayClient
		AlipayTradePrecreateRequest request = new AlipayTradePrecreateRequest();//创建API对应的request类
		if(StringUtils.isNotBlank(notifyUrl)){
			request.setNotifyUrl(notifyUrl);
		}
		request.setBizContent("{" +
				"\"out_trade_no\":\""+outTradeNo+"\"," +
				"\"total_amount\":"+totalAmount+"," +
				"\"subject\":\""+subject+"\"," +
				"\"store_id\":\""+storeId+"\"," +
				"\"timeout_express\":\""+timeoutExpress+"\"}");//设置业务参数
		AlipayTradePrecreateResponse response = alipayClient.execute(request);
		logger.info("***********二维码生成结果**********" + JSON.toJSONString(response));
		// 根据response中的结果继续业务逻辑处理
		if(response.isSuccess()){
			return CodeUtils.createTwoDimensionalCode(response.getQrCode(), outTradeNo, path, 500, 500);
		} else {
			return CommonConstants.FAIL;
		}
	}*/

	/**
	 * 查询订单状态
	 * @param appId  支付宝appid
	 * @param privateKey  商户私钥
	 * @param publicKey  商户公钥
	 * @param outTradeNo  商户订单号
	 * @return  1（交易创建，等待买家付款）、2（未付款交易超时关闭，或支付完成后全额退款）、3（交易支付成功）、4（交易结束，不可退款）
	 * 			-1查询失败
	 * @throws Exception
	 */
	public static Integer queryOrder(String appId, String privateKey, String publicKey,
						   String outTradeNo) throws Exception{
		AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.ALI_OPENAPI_URL, appId,
				privateKey, AlipayConfig.format, CommonConstants.DEFAULT_CHARSET, publicKey, "RSA2");
		AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
		request.setBizContent("{" +
				"\"out_trade_no\":\""+outTradeNo+"\"," +
				"\"trade_no\":\"\"" +
				"}");
		AlipayTradeQueryResponse response = alipayClient.execute(request);
		logger.info("***********订单查询结果**********" + JSON.toJSONString(response));
		String subCode = response.getSubCode();
		if (response.isSuccess()) {
			if(response.getTradeStatus().equals("WAIT_BUYER_PAY")){
				return 1;
			} else if (response.getTradeStatus().equals("TRADE_CLOSED")) {
				return 2;
			} else if (response.getTradeStatus().equals("TRADE_SUCCESS")) {
				return 3;
			} else {
				return 4;
			}
		} else {
			return -1;
		}
	}

	/**
	 * 交易撤销
	 * @param appId  支付宝appid
	 * @param privateKey  支付宝私钥
	 * @param publicKey  支付宝公钥
	 * @param outTradeNo  订单编号
	 * @return
	 * @throws Exception
	 */
	public static String cancelTrade(String appId, String privateKey, String publicKey,
								   String outTradeNo) throws Exception{
		AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.ALI_OPENAPI_URL, appId,
				privateKey, AlipayConfig.format, CommonConstants.DEFAULT_CHARSET, publicKey, "RSA2");
		AlipayTradeCancelRequest request = new AlipayTradeCancelRequest();
		request.setBizContent("{" +
				"\"out_trade_no\":\""+outTradeNo+"\"," +
				"\"trade_no\":\"\"" +
				"}");
		AlipayTradeCancelResponse response = alipayClient.execute(request);
		logger.info("***********订单取消结果**********" + JSON.toJSONString(response));
		if(response.isSuccess()){
			return CommonConstants.SUCCESS;
		} else {
			return CommonConstants.FAIL;
		}
	}

	/**
	 * 新版本的手机网站支付
	 * @param appId  支付宝appid
	 * @param privateKey  私钥
	 * @param publicKey  公钥
	 * @param returnUrl  同步回调地址
	 * @param notifyUrl  异步回调地址
	 * @param outTradeNo  订单编号
	 * @param totalAmount  支付金额
	 * @param subject  标题
	 * @param sellerId  收款支付宝用户ID。 如果该值为空，则默认为商户签约账号对应的支付宝用户ID
	 * @param response
	 * @throws Exception
	 */
	public static String wapPay(String appId, String privateKey, String publicKey,
					   String returnUrl, String notifyUrl, String outTradeNo,
					   String totalAmount, String subject, String sellerId,
					   HttpServletResponse response) throws Exception {
		AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.ALI_OPENAPI_URL, appId,
				privateKey, AlipayConfig.format, CommonConstants.DEFAULT_CHARSET, publicKey, "RSA2"); //获得初始化的AlipayClient
		AlipayTradeWapPayRequest alipayRequest = new AlipayTradeWapPayRequest();//创建API对应的request
		alipayRequest.setReturnUrl(returnUrl);
		alipayRequest.setNotifyUrl(notifyUrl);//在公共参数中设置回跳和通知地址
		alipayRequest.setBizContent("{" +
				"\"out_trade_no\":\""+outTradeNo+"\"," +
				"\"total_amount\":"+totalAmount+"," +
				"\"subject\":\""+subject+"\"," +
				/*"\"seller_id\":\""+sellerId+"\"," +*/
				"\"product_code\":\"QUICK_WAP_PAY\"" +
				"}");//填充业务参数
		String form = alipayClient.pageExecute(alipayRequest).getBody(); //调用SDK生成表单
		logger.info("*************alipayForm***************" + form);
		/*response.setContentType("text/html;charset=" + AlipayConfig.input_charset);
		response.getWriter().write(form);//直接将完整的表单html输出到页面
		response.getWriter().flush();
		response.getWriter().close();*/
		return form;
	}

}
